package com.chenyue.cm.api.account;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chenyue.cm.account.domain.JdAccount;
import com.chenyue.cm.account.domain.JdAccountRecord;
import com.chenyue.cm.account.service.JdAccountRecordService;
import com.chenyue.cm.account.service.JdAccountService;
import com.chenyue.cm.account.vo.AccountInfo;
import com.chenyue.cm.account.vo.AccountSource;
import com.chenyue.cm.account.vo.ChangeType;
import com.chenyue.cm.auth.Login;
import com.chenyue.cm.auth.LoginUser;
import com.chenyue.cm.bean.Success;
import com.chenyue.cm.common.constant.ConstantValues;
import com.chenyue.cm.common.constant.ErrorCode;
import com.chenyue.cm.common.constant.RedisPrefix;
import com.chenyue.cm.common.domain.JdConstantValues;
import com.chenyue.cm.common.service.JdConstantValuesService;
import com.chenyue.cm.common.vo.Page;
import com.chenyue.cm.error.domain.SysErrorRecord;
import com.chenyue.cm.error.service.SysErrorRecordService;
import com.chenyue.cm.exception.SysRuntimeException;
import com.chenyue.cm.match.domain.JdMatch;
import com.chenyue.cm.match.domain.MatchInfo;
import com.chenyue.cm.match.service.JdMatchService;
import com.chenyue.cm.match.service.JdMatchSignService;
import com.chenyue.cm.member.service.JdMemberService;
import com.chenyue.cm.order.domain.JdOrder;
import com.chenyue.cm.order.domain.JdProduct;
import com.chenyue.cm.pay.ali.AliPay;
import com.chenyue.cm.pay.ali.AliPayConfig;
import com.chenyue.cm.pay.ali.AliPayNotifyParam;
import com.chenyue.cm.pay.ali.TradeStatus;
import com.chenyue.cm.pay.iap.IosVerifyUtil;
import com.chenyue.cm.pay.wx.WXPayUtil;
import com.chenyue.cm.pay.wx.WxConfig;
import com.chenyue.cm.pay.wx.WxNotify;
import com.chenyue.cm.pay.wx.WxPayConstants;
import com.chenyue.cm.payment.service.JdOrderService;
import com.chenyue.cm.payment.service.JdProductService;
import com.chenyue.cm.user.domain.JdAppUser;
import com.chenyue.cm.user.service.JdAppUserService;
import com.chenyue.cm.utils.DateUtils;
import com.chenyue.cm.utils.RedisUtils;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author libingxing
 * @date 2021-07-07
 */
@Api(value = "账户模块", tags = "账户模块")
@ApiSort(3)
@RestController
@RequestMapping("/api/account")
public class JdAccountController {

    private final JdAccountService accountService;

    private final JdAccountRecordService accountRecordService;

    private final JdMatchSignService matchSignService;

    private final JdOrderService orderService;

    private final JdAppUserService appUserService;

    private final SysErrorRecordService errorRecordService;

    private final JdProductService productService;

    private final JdMemberService memberService;

    private final JdMatchService matchService;

    private final WxConfig wxConfig;

    private final RedisUtils redisUtils;

    private final JdConstantValuesService constantValuesService;

    public JdAccountController(
            JdAccountService jdAccountService,
            JdAccountRecordService accountRecordService,
            JdMatchSignService matchSignService, JdOrderService orderService,
            JdAppUserService appUserService,
            SysErrorRecordService errorRecordService,
            JdProductService productService,
            JdMemberService memberService,
            JdMatchService matchService, WxConfig wxConfig,
            RedisUtils redisUtils, JdConstantValuesService constantValuesService) {
        this.accountService = jdAccountService;
        this.accountRecordService = accountRecordService;
        this.matchSignService = matchSignService;
        this.orderService = orderService;
        this.appUserService = appUserService;
        this.errorRecordService = errorRecordService;
        this.productService = productService;
        this.memberService = memberService;
        this.matchService = matchService;
        this.wxConfig = wxConfig;
        this.redisUtils = redisUtils;
        this.constantValuesService = constantValuesService;
    }

    /**
     * 账户
     *
     * @param changeType 不传全部 1支出 2收入
     * @return account record
     */
    @Login
    @GetMapping("/account")
    @ApiOperation(value = "查询账户信息", notes = "查询账户信息")
    @ApiOperationSupport(order = 1)
    @ApiImplicitParams({
            @ApiImplicitParam(value = "页数", name = "page", dataType = "integer"),
            @ApiImplicitParam(value = "条数", name = "rows", dataType = "integer"),
            @ApiImplicitParam(value = "身份 1 用户 2 机构", name = "role", dataType = "integer"),
            @ApiImplicitParam(value = "不传全部 1支出 2收入", name = "changeType", dataType = "string"),
            @ApiImplicitParam(value = "变动来源 6提现 7比赛收款", name = "source", dataType = "string")
    })
    public Success<AccountInfo> account(
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "10") Integer rows,
            @ApiIgnore @LoginUser JdAppUser user,
            Integer changeType, Integer source,
            @RequestParam(defaultValue = "1") Integer role
    ) {
        Double amount = 0D;
        if (role == 1) {
            amount = accountService.getAccount(Integer.valueOf(user.getId())).getAmount();
        }
        if (role == 2) {
            amount = accountService.getWithdrawAbleAmount(Integer.valueOf(user.getId()));
        }
        final JdAccount account = new JdAccount();
        account.setAmount(amount);
        LambdaQueryWrapper<JdAccountRecord> wrapper = new QueryWrapper<JdAccountRecord>().lambda();
        if (changeType != null && changeType > 0) {
            wrapper.eq(JdAccountRecord::getChangeType, changeType);
        }
        if (source != null && source > 0) {
            wrapper.eq(JdAccountRecord::getSource, source);
        } else {
            if (role == 2) {
                wrapper.in(JdAccountRecord::getSource, Arrays.asList(AccountSource.WITHDRAW, AccountSource.MATCH_SIGN));
            } else {
                wrapper.notIn(JdAccountRecord::getSource, Arrays.asList(AccountSource.WITHDRAW, AccountSource.MATCH_SIGN));
            }
        }
        wrapper.eq(JdAccountRecord::getUserId, user.getId());

        int total = accountRecordService.count(wrapper);
        Page<List<JdAccountRecord>> result = new Page<>(page, rows, total);
        wrapper.orderByDesc(JdAccountRecord::getCt);
        List<JdAccountRecord> list = accountRecordService.list(wrapper.last(result.convertPage()));
        for (JdAccountRecord record : list) {
            if (role == 2) {
                final JdConstantValues one = constantValuesService.lambdaQuery().eq(JdConstantValues::getConstantKey, ConstantValues.EXCHANGE_RATE).one();
                record.setAmount(record.getAmount() / (one == null ? 1 : Double.parseDouble(one.getConstantValue())));
            }
            if (record.getSource() == AccountSource.MATCH_SIGN) {
//                如果是比赛收款，提供比赛数据
                if (record.getOrderId() == 0) {
                    continue;
                }
                final JdOrder order = orderService.lambdaQuery().eq(JdOrder::getId, record.getOrderId()).one();
                if (order != null) {
                    final MatchInfo matchInfo = matchService.matchInfo(order.getProductId(), null);
                    if (matchInfo != null) {
                        record.setRemark(matchInfo.getSignCount() + "");
                    }
                }
            }
        }
        result.setContent(list);
        final AccountInfo info = new AccountInfo();
        info.setAccount(account);
        info.setResult(result);
        return Success.success(info);
    }

    /**
     * 微信支付回调
     */
    @RequestMapping("/wxRecharge")
    @Transactional(rollbackFor = Exception.class)
    public String wxRecharge(
            HttpServletRequest request
    ) throws Exception {
        //获取回调信息,执行业务逻辑
        BufferedReader reader = request.getReader();
        String line;
        StringBuilder requestParam = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            requestParam.append(line);
        }
        request.getReader().close();
        System.out.println("-------------------------------------------------接收到的报文---------------------------------------------");
        System.out.println("----接收到的报文---" + requestParam + "----接收到的报文---");
        System.out.println("-------------------------------------------------接收到的报文---------------------------------------------");
        Map<String, String> result = WXPayUtil.xmlToMap(requestParam.toString());
//        转化实体类
        WxNotify wxResult = WXPayUtil.mapToEntity(result, WxNotify.class);
        if (WxPayConstants.SUCCESS.equalsIgnoreCase(wxResult.getReturn_code())) {
//            请求成功
            if (WxPayConstants.SUCCESS.equalsIgnoreCase(wxResult.getResult_code())) {
//                交易成功 验签
                if (WXPayUtil.isSignatureValid(result, wxConfig.getKey())) {
//                    验签成功
                    JdOrder order = orderService.selectByPrimaryKey(wxResult.getOut_trade_no());
                    if (order == null) {
//                        订单不存在
                        return WxPayConstants.FAIL;
                    }
                    if (order.getProductPrice() * 100 == wxResult.getTotal_fee()) {
//                        交易金额与订单记录吻合   **完成交易**
                        orderService.tradeFinish(order.getId(), wxResult.getTransaction_id(), order.getProductPrice() * 100, order.getUserId());
//                        交易内容判定  发货
                        convertTransaction(order);
                        return WxPayConstants.SUCCESS;
                    } else {
//                        交易金额与订单不符
                        errorRecordService.saveErrorRecord("交易金额与订单不符", JSON.toJSONString(order));
                        return WxPayConstants.FAIL;
                    }
                } else {
//                    验签失败
                    errorRecordService.saveErrorRecord("验签失败", JSON.toJSONString(wxResult));
                    return WxPayConstants.FAIL;
                }
            } else {
//                交易失败
                errorRecordService.saveErrorRecord("交易失败", JSON.toJSONString(wxResult));
                return WxPayConstants.FAIL;
            }
        } else {
//            接口请求失败
            errorRecordService.saveErrorRecord("交易金额与订单不符", JSON.toJSONString(wxResult));
            return WxPayConstants.FAIL;
        }
    }

    /**
     * 阿里充值支付回调
     */
    @RequestMapping("/aliRecharge")
    @Transactional(rollbackFor = Exception.class)
    public String aliRecharge(HttpServletRequest request) throws Exception {
        Map<String, String> params = AliPay.convertRequestParamsToMap(request);
        System.out.println("回调接受到的参数：" + params);
        // 调用SDK验证签名
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AliPayConfig.ALIPAY_PUBLIC_KEY, AliPayConfig.CHARSET, AliPayConfig.SIGNTYPE);
        if (signVerified) {
            AliPayNotifyParam aliParams = AliPay.buildAliPayNotifyParam(params);
            if (TradeStatus.TRADE_SUCCESS.getValue().equalsIgnoreCase(aliParams.getTradeStatus())) {
                //根据订单id，查询订单信息
                String orderId = aliParams.getPassBackParams();
                JdOrder order = orderService.selectByPrimaryKey(orderId);
                if (order == null) {
                    System.out.println("查询不到该订单：");
                    return AliPay.FAILURE;
                }
                if (order.getProductPrice() != aliParams.getTotalAmount().doubleValue()) {
                    System.out.println("实际支付和订单价格不一致-实际支付：" + aliParams.getTotalAmount().doubleValue() + "&订单价格：" + order.getOrderAmount());
                    return AliPay.FAILURE;
                }
                //修改订单 交易明细
                orderService.tradeFinish(order.getId(), aliParams.getTradeNo(), order.getProductPrice() * 100, order.getUserId());
//                判定交易内容 发货
                convertTransaction(order);
                return AliPay.SUCCESS;
            } else {
                //记录错误
                try {
                    System.err.println("签名错误");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } else {
            System.out.println("验签失败！");
            return AliPay.FAILURE;
        }
        return AliPay.FAILURE;
    }

    @PostMapping("/iosRecharge")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "ios支付验证", notes = "ios支付验证")
    @ApiOperationSupport(order = 2)
    @ApiImplicitParams({
            @ApiImplicitParam(value = "订单id", name = "orderId", dataType = "string", required = true),
            @ApiImplicitParam(value = "用户id", name = "user", dataType = "string", required = true),
            @ApiImplicitParam(value = "事务id", name = "transactionId", dataType = "string", required = true),
            @ApiImplicitParam(value = "支付验证内容", name = "payload", dataType = "string", required = true),
    })
    public Success<Object> iosRecharge(
            String orderId, Integer user,
            String transactionId, String payload
    ) {
        if (StringUtils.isEmpty(transactionId)) {
            return Success.error("事务id不能为空");
        }

        //线上环境验证  0沙箱 1线上
        String verifyResult = IosVerifyUtil.buyAppVerify(payload, 1);

        if (StringUtils.isEmpty(verifyResult)) {
            return Success.error("苹果服务器验证失败");
        }

        String result = IosVerifyUtil.verifyAppleOrder(verifyResult, transactionId, payload);

        if (StringUtils.isNotBlank(result)) {
            return Success.error(result);
        }

        JdOrder order = orderService.selectByPrimaryKey(orderId);

        if (order == null) {
            return Success.error("订单信息异常");
        }

        if (!user.equals(order.getUserId())) {
            return Success.error("非本人订单信息");
        }

        if (order.getOrderStatus() == 2) {
            return Success.error("请勿重复验证");
        }

//        验证完成 走订单逻辑 充值
        orderService.tradeFinish(Integer.valueOf(orderId), transactionId, order.getProductPrice() * 100, order.getUserId());

        convertTransaction(order);

        return Success.success("交易成功", "");
    }

    private void convertTransaction(JdOrder order) {
        order = orderService.getById(order.getId());
        final JSONObject json = redisUtils.get(RedisPrefix.TEMP_ORDER + order.getId(), JSONObject.class);
        if (json == null) {
           throw new SysRuntimeException("订单已过期");
        }
        switch (json.getInteger("type")) {
            case 1:
//                金币充值
                recharge(order.getUserId(), order.getId());
                break;
            case 2:
//                会员充值
                final JdProduct product = productService.getById(order.getProductId());
                if (product == null) {
                    throw new SysRuntimeException("商品不能为空");
                }
                memberService.rechargeMember(order.getUserId(), product, order.getId());
                JdConstantValues one = constantValuesService.lambdaQuery().eq(JdConstantValues::getConstantKey, ConstantValues.MEMBER_RECHARGE).one();
                if (one == null) {
                    one = new JdConstantValues();
                    one.setConstantValue("0");
                }
                accountService.recharge(order.getUserId(), Double.parseDouble(one.getConstantValue()), AccountSource.MEMBER_RECHARGE, order.getId());
                break;
            default:
                //            赛事报名
//                发布方 比赛收款
                final JdMatch match = matchService.getById(order.getProductId());
                if (match == null) {
                    SysErrorRecord error = new SysErrorRecord();
                    error.setTitle("三方金币收款，订单没赛事id");
                    error.setUserId(order.getUserId());
                    error.setRemark(order.getProductId() + "");
                    errorRecordService.save(error);
                    break;
                }
//                    判断支付方式 1纯金币 2纯钱
                if (match.getPayType() == 1) {
                    accountService.recharge(match.getCu(), order.getOrderAmount(), AccountSource.MATCH_SIGN, order.getId());
                }
                if (match.getPayType() == 2) {
//                    换算成金币入账
                    String constantValue = getExchangeRate().getConstantValue();
                    double amount = order.getOrderAmount() * Double.parseDouble(constantValue);
                    order.setOrderAmount(amount);
                    accountService.recharge(match.getCu(), amount, AccountSource.MATCH_SIGN, order.getId());
                }
//                金币返利
                matchSignService.updateSignAndGoldBack(order);
                break;
        }
        redisUtils.delete(RedisPrefix.TEMP_ORDER + order.getId());
    }

    @Login
    @PostMapping("goldPresent")
    @ApiOperation("金币转增")
    @ApiOperationSupport(order = 1)
    @ApiImplicitParams({
            @ApiImplicitParam(value = "赠送金额", name = "amount", dataType = "string", required = true),
            @ApiImplicitParam(value = "转赠账号/id", name = "givenAccount", dataType = "string", required = true)
    })
    @Transactional(rollbackFor = Exception.class)
    public Success<String> goldPresent(
            @ApiIgnore @LoginUser JdAppUser user,
            Double amount, String givenAccount
    ) {
        LambdaQueryWrapper<JdAppUser> eq = new QueryWrapper<JdAppUser>().lambda()
                .eq(JdAppUser::getUserNum, givenAccount).last("limit 1");
        JdAppUser one = appUserService.getOne(eq);
        if (one == null) {
            eq.clear();
            eq.eq(JdAppUser::getMobile, givenAccount).last("limit 1");
            one = appUserService.getOne(eq);
            if (one == null) {
                return Success.error(ErrorCode.MOBILE_UN_REGISTER.getMsg());
            }
        }
        final JdAccount account = accountService.getAmount(Integer.valueOf(one.getId()));
        if (account.getAmount() < amount) {
            return Success.error("可用余额不足");
        }
        JdAccountRecord record = new JdAccountRecord();
        record.setAmount(amount);
        record.setChangeType(ChangeType.INCOME);
        record.setSource(AccountSource.PRESENT);
        record.setUserId(Integer.valueOf(one.getId()));
        record.setCt(DateUtils.getToday());
        boolean save = accountRecordService.save(record);
        if (!save) {
            throw new SysRuntimeException(ErrorCode.INSERT_ERROR.getMsg());
        }
        record = new JdAccountRecord();
        record.setAmount(amount);
        record.setChangeType(ChangeType.PAY);
        record.setSource(AccountSource.PRESENT);
        record.setUserId(Integer.valueOf(user.getId()));
        record.setCt(DateUtils.getToday());
        save = accountRecordService.save(record);
        if (!save) {
            throw new SysRuntimeException(ErrorCode.INSERT_ERROR.getMsg());
        }
        return Success.success();
    }

    @Login
    @PostMapping("/GoldPay")
    @ApiOperation("赛事金币报名")
    @ApiOperationSupport(order = 1)
    @Transactional(rollbackFor = Exception.class)
    public Success<String> goldPay(
            @ApiIgnore @LoginUser JdAppUser user,
            @ApiParam @RequestBody JdOrder order
    ) {
        if (!user.getId().equals(order.getUserId())) {
            return Success.error();
        }
//        验证订单
        orderService.tradeFinish(order.getId(), "", order.getProductPrice() * 100, order.getUserId());
        final String costume = accountService.costume(order.getUserId(), order.getProductPrice(), AccountSource.CUSTOM, order.getId());
        if (StringUtils.isNotBlank(costume)) {
            throw new SysRuntimeException(costume);
        }
        convertTransaction(order);
        return Success.success();
    }

    @Transactional(rollbackFor = Exception.class)
    void recharge(Integer userId, Integer orderId) {
        JdOrder order = orderService.getById(orderId);
        if (order == null) {
            errorRecordService.saveErrorRecord("订单走丢了", userId + "_" + orderId);
            return;
        }

        final JdConstantValues one = getExchangeRate();
        double v = Integer.parseInt(one.getConstantValue()) * order.getProductPrice();
        String errorMsg = accountService.recharge(userId, v, AccountSource.GOLD_RECHARGE, orderId);
        if (StringUtils.isNotBlank(errorMsg)) {
            errorRecordService.saveErrorRecord(errorMsg, userId + "_" + orderId);
        }
    }

    private JdConstantValues getExchangeRate() {
        return constantValuesService.lambdaQuery().eq(JdConstantValues::getConstantKey, ConstantValues.EXCHANGE_RATE).one();
    }

}
